<?php
/**
 * Created by PhpStorm.
 * User: Mysic
 * Date: 2020/10/21
 * Time: 16:43
 */

namespace app\admin\service\fix;

use think\Exception;
use Throwable;
use org\RabbitMQ;
use think\Env;
use think\Request;
use app\factory\MqFactory;
use app\mocks\extend\MockWeChatPay;
use app\mocks\extend\MockWeChatProfitSharing;
use app\common\model\divide\Receive;
use app\common\model\divide\ReceiveUser;
use app\common\model\divide\Refund;
use app\common\model\divide\Service;
use app\common\model\divide\System;
use app\common\model\divide\Store;
use app\common\model\VipCardOrder;
use app\common\model\dealer\Capital;
use app\common\model\Wxapp as WxappModel;
use app\common\model\Order;
use app\common\model\User;
use app\common\model\Wxsetting;
use app\common\model\Agent;
use app\common\model\dealer\User as DealUser;
use app\common\mysic\bonus\BonusHandler;
use app\common\mysic\bonus\BonusReceiveOp;
use app\common\mysic\bonus\BonusReceiveUserOp;
use app\common\library\wechat\Abonus;
use app\common\library\wechat\WxPay;
use app\common\library\MysicLog;
use app\common\mysic\bonus\BonusRefundOp;
use app\common\mysic\order\UserOrderOp;
use app\common\mysic\order\VipCardHandler;
use app\common\mysic\user\DealUserAccountOp;
use app\common\mysic\user\UserAccountOp;
use app\common\mysic\order\AgentDividendOrderOp;
use app\common\mysic\order\StoreDividendOrderOp;
use app\common\mysic\dividend\AgentDividendHandler;
use app\common\mysic\dividend\StoreDividendHandler;
use app\common\mysic\dividend\SystemDividendHandler;
use app\common\mysic\order\SystemDividendOrderOp;
use utils\Services;


class BonusFix
{
    /**
     * @var MysicLog|null 自定义log
     */
    protected $log;
    /**
     * @var $rmq RabbitMQ 句柄
     */
    protected $rmq;
    /**
     * @var SystemDividendHandler 平台分账处理器
     */
    protected $systemDividendHandler;
    /**
     * @var AgentDividendHandler 代理商分账处理器
     */
    protected $agentDividendHandler;
    /**
     * @var StoreDividendHandler 商户分账处理器
     */
    protected $storeDividendHandler;
    /**
     * @var BonusHandler 用户分红（退款）处理器
     */
    protected $bonusHandler;
    /**
     * @var User 用户模型
     */
    protected $userModel;
    /**
     * @var Agent 代理商模型
     */
    protected $agentModel;
    /**
     * @var System 平台分账订单模型
     */
    protected $divideSystemModel;
    /**
     * @var Service 代理商分账订单模型
     */
    protected $divideAgentModel;
    /**
     * @var Store 商户分账订单模型
     */
    protected $divideStoreModel;
    /**
     * @var Wxsetting 商户分红设置模型
     */
    protected $bonusSettingModel;
    /**
     * @var Order 用户订单模型
     */
    protected $userOrderModel;
    /**
     * @var WxappModel 微信小程序模型
     */
    protected $miniProgramModel;
    /**
     * @var SystemDividendOrderOp 平台分账订单模型操作器
     */
    protected $systemDividendOrderOp;
    /**
     * @var AgentDividendOrderOp 代理商分账订单模型操作器
     */
    protected $agentDividendOrderOp;
    /**
     * @var StoreDividendOrderOp 商户分账订单模型操作器
     */
    protected $storeDividendOrderOp;
    /**
     * @var Abonus 原支付分账类
     */
    protected $dividendBonusApi;
    /**
     * @var BonusReceiveOp 用户分红记录操作器
     */
    protected $bonusReceiveOp;
    /**
     * @var Receive
     */
    protected $bonusReceiveModel;
    /**
     * @var ReceiveUser
     */
    protected $bonusReceiveUserModel;
    /**
     * @var WxPay
     */
    protected $wxPayApi;
    /**
     * @var BonusReceiveUserOp
     */
    protected $bonusReceiveUserOp;
    /**
     * @var Refund
     */
    protected $bonusRefundModel;
    /**
     * @var BonusRefundOp
     */
    protected $bonusRefundOp;
    /**
     * @var VipCardOrder
     */
    protected $cardOrderModel;
    /**
     * @var VipCardHandler
     */
    protected $cardOrderHandler;
    /**
     * @var DealUserAccountOp
     */
    protected $dealUserAccountOp;
    /**
     * @var UserAccountOp
     */
    protected $userAccountOp;
    /**
     * @var Capital
     */
    protected $dealUserCapitalModel;
    /**
     * @var DealUser
     */
    protected $dealUserModel;
    /**
     * @var UserOrderOp
     */
    protected $userOrderOp;
    /**
     * @var Request
     */
    protected $request;
    protected $returnResult;
    protected $userOrderEntity;
    protected $bonusSettingEntity;
    protected $issue;
    protected $joinShareHolder;
    protected $bonusAble;
    protected $selfBonusAble;
    protected $dividendAble;
    protected $bonusUpperLimit;
    protected $bonus;
    protected $totalBonus;
    protected $bonusUserCount;
    protected $agentEntity;
    protected $miniProgramEntity;
    protected $agentId;
    protected $allAgent;
    protected $userReceives;

    public function __construct($orderNo)
    {
        $this->request = Request::instance();
        $this->rmq = MqFactory::instance();
        $this->log = MysicLog::instance();
        $this->log->setFilename('fix/bonus');
        $this->returnResult = new ReturnResult();
        $this->init();
        $this->getOrderEntity($orderNo);
        $this->initData();
    }

    protected function getOrderEntity($orderNo)
    {
        $orderEntity = $this->userOrderModel->where('order_no', $orderNo)->find();
        if(!$orderEntity) {
            throw new Exception('订单号不存在');
        }
        $this->userOrderEntity = $orderEntity;
    }

    protected function initData()
    {
        $this->bonusSettingEntity = $this->bonusSettingModel->where('wxapp_id', $this->userOrderEntity->wxapp_id)->find();
        $this->bonusUpperLimit = bcmul(strval($this->userOrderEntity->pay_price), bcdiv(strval($this->bonusSettingEntity->upline), '100',2),2);
        $this->issue = $this->bonusSettingEntity->periods_num ?? 0;
        //初始化此订单支付人是否加入分红队列并更新微股东身份
        $this->joinShareHolder = true;
        //初始化此订单是否给其他用户分红
        $this->bonusAble = true;
        //初始化此订单是否给自己分红
        $this->selfBonusAble = true;
        //初始化是否分账
        $this->dividendAble = true;
        // 初始化分红上限金额 本次分红平均金额 本次分红总金额
        $this->bonusUpperLimit = 0;
        $this->bonus = 0;
        $this->totalBonus = 0;
        try {
            if ($this->userOrderEntity->order_source == 40) {
                $this->cardOrderHandler->setModel($this->cardOrderModel)->setUserOrder($this->userOrderEntity)->instanceCardEntity();
                if($this->cardOrderHandler->getBonusRate() > 0) {
                    $this->bonusSettingEntity->rewardpercent = $this->cardOrderHandler->getBonusRate();
                }
            }
        } catch (Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }

        $this->userReceives   = $this->bonusReceiveModel
            ->where(['wxapp_id' => $this->userOrderEntity->wxapp_id, 'type' => 0, 'periods_num' => $this->bonusSettingEntity->periods_num])
            ->whereTime('finish_time', '>', time())
            ->field('receives_id,type,order_no, times,balance,wxapp_id,payment,periods_num,user_id,account,top_limit,transaction_id')
            ->order('create_time desc')
            ->select()->toArray();

        $this->bonusUserCount = count($this->userReceives);
        // 本期活动分红队列为空，不给其他用户分
        if($this->bonusUserCount < 1 || $this->bonusSettingEntity->start_time > time()) {
            $this->bonusAble = false;
        }
        //活动设置不存在 |  活动未开始 | 活动已关闭 | 商品不是虚拟商品 | 订单金额未达到参与活动最低金额， 本订单用户身份不更新为微股东,不分红
        if(!$this->bonusSettingEntity || $this->bonusSettingEntity->start_time > time()
//            || $this->bonusSettingEntity->status != 1
            || $this->userOrderEntity->is_fictitious != 1 || $this->userOrderEntity->pay_price < $this->bonusSettingEntity->money)
        {
            $log = [
                '活动设置是否存在' => bool2str(isset($this->bonusSettingEntity)),
                '活动未开始' => bool2str($this->bonusSettingEntity->start_time > time()),
                '活动已关闭' => bool2str($this->bonusSettingEntity->status != 1),
                '商品不是虚拟商品' => bool2str($this->userOrderEntity->is_fictitious != 1),
                '订单金额未达到参与活动最低金额' => bool2str($this->userOrderEntity->pay_price < $this->bonusSettingEntity->money)
            ];
            $this->log->info($log, '条件判断结果');
            $log = [
                '用户不更新为微股东' => true,
                '不给用户分红' => true
            ];
            $this->log->info($log, '条件判断结果');
            $this->joinShareHolder = false;
            $this->selfBonusAble = false;
        }
        //计算本次分红的分红上限 分红金额
        if($this->bonusSettingEntity && ($this->bonusAble || $this->selfBonusAble)) {
            if(!$this->selfBonusAble) {
                $this->bonusUserCount--;
            }
            $this->bonusUpperLimit = bcmul(strval($this->userOrderEntity->pay_price), bcdiv(strval($this->bonusSettingEntity->upline), '100',2),2);
            $this->bonus = $this->bonusHandler
                ->setBonusSetting($this->bonusSettingEntity)
                ->setUserOrder($this->userOrderEntity)
                ->calculateBonus($this->bonusUserCount)
                ->getBonus();
            $this->totalBonus = $this->bonusHandler->getTotalBonus();
        }
        // 分红金额小于1分钱 ,所有用户不分红
        if($this->bonus <= 0) {
            $this->bonusAble = false;
            $this->selfBonusAble = false;
        }
        //商品不是虚拟商品， 不给平台、代理商、商户分账
        if($this->userOrderEntity->is_fictitious != 1) {
            $this->log->info('', '商品是实物商品，不给平台、代理商、商户分账');
            $this->dividendAble = false;
        }
        $this->agentId = $this->miniProgramModel->where(['wxapp_id' => $this->userOrderEntity->wxapp_id])->value('agent_id');
        $this->agentEntity = $this->agentModel->where('agent_id', $this->agentId)->find();
        $this->miniProgramEntity = $this->miniProgramModel->where(['wxapp_id' => $this->userOrderEntity->wxapp_id])->find();
        $this->allAgent = $this->agentModel->where(['is_recycle' => 0, 'status'     => 1, 'is_delete'  => 0])->order('agent_id desc')->select()->toArray();

    }

    public function finishDividend()
    {
//        if($this->dividendAble) {
//            return $this->returnResult->setFailure()->setMsg('此订单可分账，不能执行订单完结');
//        }
        $this->systemDividendOrderOp->setOrder($this->userOrderEntity);
        try {
            $ret = $this->systemDividendHandler->setOp($this->systemDividendOrderOp)->setDividendApi($this->dividendBonusApi)->dividendOver('实物商品，不作分账，完结分账订单');
            if(!$ret) {
                $this->returnResult->setFailure()->setMsg('完结订单失败');
            } else {
                $this->returnResult->setSuccess();
            }
        } catch(Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function userUpgrade()
    {
        if(!$this->joinShareHolder) {
            return $this->returnResult->setFailure()->setMsg('订单不满足用户升级微股东的条件，升级微股东失败，请检查订单数据并更改后再试');
        }
        try {
            $userEntity = $this->userModel->where('user_id', $this->userOrderEntity->user_id)->find();
            if ($userEntity->shareholder == 0) {
                $userEntity->shareholder = 1;
                $ret = $userEntity->save();
                if (!$ret) {
                    $this->returnResult->setFailure()->setMsg('用户升级为微股东失败');
                }else{
                    $this->returnResult->setSuccess();
                }
            }
        } catch (Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function joinReceives()
    {
        if(!$this->joinShareHolder) {
            return $this->returnResult->setFailure()->setMsg('订单不满足用户升级微股东的条件，入分红队列失败，请检查订单数据并更改后再试');
        }
        try {
            $ret = $this->bonusReceiveOp
                ->setBonusSetting($this->bonusSettingEntity)
                ->setUserOrder($this->userOrderEntity)
                ->setUserModel($this->userModel)
                ->setModel($this->bonusReceiveModel)
                ->setUpperLimit($this->bonusUpperLimit)
                ->setBonus($this->bonus)
                ->create();
            if (!$ret) {
                $this->returnResult->setFailure()->setMsg('入分红队列失败');
            } else {
                $this->returnResult->setSuccess();
            }
        } catch (Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function callWxRefund()
    {
        if(!$this->selfBonusAble) {
            return $this->returnResult->setFailure()->setMsg('当次订单不满足分红的条件，请检查订单数据并更改后再试');
        }
        try {
            //获取微信接口配置
            $wxConfig = WxappModel::getWxappRedis($this->userOrderEntity->wxapp_id);
        } catch (Throwable $e) {
            return $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        //发起微信退款申请
        try {
            $this->wxPayApi->setConfigArr($wxConfig);
            // 分红上限小于分红金额， 按上限金额分红
            if(($this->bonusUpperLimit - $this->bonus) < 0) {
                $this->bonusHandler->setBonus($this->bonusUpperLimit);
            } else {
                $this->bonusHandler->setBonus($this->bonus);
            }
            $ret = $this->bonusHandler->setApi($this->wxPayApi)->run();
            if(!$ret) {
                $this->returnResult->setFailure()->setMsg('当次订单分红失败');
            } else {
                $this->returnResult->setSuccess();
            }
        } catch (Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function receivesUserAppend()
    {
        $receivesEntity = $this->bonusReceiveModel->where('order_no', $this->userOrderEntity->order_no)->find();
        if(!$receivesEntity) {
            $this->log->error('未找到分红队列主表信息');
            return $this->returnResult->setFailure()->setMsg('未找到分红队列主表信息');
        }
        try {
            $this->log->info('开始', '添加用户本次分红到分红用户记录副表');
            $this->bonusReceiveUserOp
                ->setModel($this->bonusReceiveUserModel)
                ->setBonusSetting($this->bonusSettingEntity)
                ->setReceiveEntity($receivesEntity)
                ->setRefundData(['refund_id' => 'fixed_frefund_log'])
                ->setRefundType(1)
                ->setBonus($this->bonusHandler->getBonus())
                ->create();
        } catch (Throwable $e) {
            $this->log->error(exceptionLogFormat($e), '设置Operator参数时抛出异常');
           $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        $this->returnResult->setSuccess();
        return $this->returnResult;
    }

    public function finishReceives()
    {
        if(($this->bonusUpperLimit - $this->bonus) > 0) {
            return $this->returnResult->setFailure()->setMsg('此订单分红未达到完结条件，不能完结，请检查此订单分红队列数据并更改后完结');
        }
        $receivesEntity = $this->bonusReceiveModel->where('order_no', $this->userOrderEntity->order_no)->find();
        if(!$receivesEntity) {
            $this->log->error('未找到分红队列主表信息');
            return $this->returnResult->setFailure()->setMsg('未找到分红队列主表信息');
        }
        try {
            $this->bonusReceiveOp
                ->setUserModel($this->userModel)
                ->setReceiveEntity($receivesEntity)
                ->setBonus($this->bonus)
                ->update($this->bonusReceiveOp::FINISHED, $this->bonusReceiveOp::BONUS_REFUND);
            $this->returnResult->setSuccess();
        } catch (Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function systemDividendCreate()
    {
        try {
            $ret = $this->systemDividendOrderOp
                ->setIssue($this->issue)
                ->setModel($this->divideSystemModel)
                ->setAgentEntity($this->agentEntity)
                ->setOrder($this->userOrderEntity)
                ->create();
            if (!$ret) {
               $this->returnResult->setFailure()->setMsg('创建系统分账订单失败');
            } else {
                $this->returnResult->setSuccess();
            }
        } catch (Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function serviceDividendCreate()
    {
        try {
            $this->agentDividendOrderOp->setModel($this->divideAgentModel)->setOrder($this->userOrderEntity);
            if (!empty($this->agentId) && !empty($this->allAgent)) {
                $tree = Services::instance();
                $tree->init($this->allAgent, 'recommend_id');
                $agentList = $tree->getParents($this->agentId, true);
                $ret = $this->agentDividendOrderOp->setAgents($agentList)->setIssue($this->issue)->create();
                if (!$ret || count($agentList) != $ret) {
                    $this->returnResult->setFailure()->setMsg('代理商分账订单入库数据存在失败');
                }else{
                    $this->returnResult->setSuccess();
                }
            }
        } catch (Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function storeDividendCreate()
    {
        try {
            $ret =  $this->storeDividendOrderOp
                ->setModel($this->divideStoreModel)
                ->setOrder($this->userOrderEntity)
                ->setTotalBonus($this->totalBonus)
                ->setMiniProgramEntity($this->miniProgramEntity)
                ->setBonusSettingEntity($this->bonusSettingEntity)
                ->setIssue($this->issue)
                ->create();
            if (!$ret) {
                $this->returnResult->setFailure()->setMsg('创建服务商分账订单失败');
            } else {
                $this->returnResult->setSuccess();
            }
        } catch (Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function callWxDividend()
    {
        $dividendSystemEntity = $this->divideSystemModel->where('order_no', $this->userOrderEntity->order_no)->find();
        $this->systemDividendOrderOp->setOrder($this->userOrderEntity)->setModel($dividendSystemEntity);
        $this->systemDividendHandler->setOp($this->systemDividendOrderOp);
        try {
            $this->log->info('开始','调用微信分账接口');
            $ret = $this->systemDividendHandler->setDividendApi($this->dividendBonusApi)->setOp($this->systemDividendOrderOp)->doDividend();
            if(!$ret) {
               $this->returnResult->setFailure()->setMsg('调用微信分账申请接口失败');
            }else{
                $this->returnResult->setSuccess();
            }
        } catch (Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        $this->log->info('结束','调用微信分账接口');
        return $this->returnResult;
    }

    public function updateSystemDividend()
    {
        $dividendSystemEntity = $this->divideSystemModel->where('order_no', $this->userOrderEntity->order_no)->find();
        $this->systemDividendOrderOp->setModel($dividendSystemEntity);
        try {
            $this->systemDividendOrderOp->success();
            $this->returnResult->setSuccess();
        } catch(Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function updateServiceDividend()
    {
        $this->agentDividendOrderOp->setOrder($this->userOrderEntity)->setModel($this->divideAgentModel);
        try {
            $this->agentDividendOrderOp->success();
            $this->returnResult->setSuccess();
        } catch(Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function updateStoreDividend()
    {
        $dividendStoreOrderEntity = $this->divideStoreModel->where('order_no', $this->userOrderEntity->order_no)->find();
        $this->storeDividendOrderOp->setModel($dividendStoreOrderEntity);
        try{
            $this->storeDividendOrderOp->success();
            $this->returnResult->setSuccess();
        } catch(Throwable $e) {
            $this->returnResult->setFailure()->setMsg($e->getMessage());
        }
        return $this->returnResult;
    }

    public function otherJoinBonusQueue()
    {
        if (!$this->bonusAble) {
            return $this->returnResult->setFailure()->setMsg('不符合给其他人分红的判断条件，不能给其他人分红，请检查此订单分红队列数据并更改后再试');
        }
        foreach ($this->userReceives as $receive) {
            $msgList[] = $rmqMsg = [
                'receives_id'    => $receive[ 'receives_id' ],
                'bonus'          => $this->bonusHandler->getBonus(),
                'reward_percent' => $this->bonusSettingEntity->rewardpercent,
                'order_id' =>  $this->userOrderEntity->order_id
            ];
//                            $wxMerchantId = $this->miniProgramModel->where(['wxapp_id' => $userOrderEntity->wxapp_id])->value('mchid');//todo 按商户mchid号，入列
            $this->rmq->send($rmqMsg, 'merchant', 'bonus', 'bonus');
        }
        $this->returnResult->setSuccess();
        return $this->returnResult;
    }

    protected function init()
    {
        $this->systemDividendHandler = new SystemDividendHandler();
        $this->agentDividendHandler  = new AgentDividendHandler();
        $this->storeDividendHandler  = new StoreDividendHandler();
        $this->bonusHandler          = new BonusHandler();
        $this->systemDividendOrderOp = new SystemDividendOrderOp();
        $this->agentDividendOrderOp  = new AgentDividendOrderOp();
        $this->storeDividendOrderOp  = new StoreDividendOrderOp();
        $this->bonusReceiveOp        = new BonusReceiveOp();
        $this->bonusReceiveUserOp    = new BonusReceiveUserOp();
        $this->bonusRefundOp         = new BonusRefundOp();
        $this->cardOrderHandler      = new VipCardHandler();
        $this->userOrderModel        = new Order();
        $this->userModel             = new User();
        $this->bonusSettingModel     = new Wxsetting();
        $this->divideAgentModel      = new Service();
        $this->divideSystemModel     = new System();
        $this->divideStoreModel      = new Store();
        $this->miniProgramModel      = new WxappModel();
        $this->agentModel            = new Agent();
        $this->bonusReceiveModel     = new Receive();
        $this->bonusReceiveUserModel = new ReceiveUser();
        $this->bonusRefundModel      = new Refund();
        $this->cardOrderModel        = new VipCardOrder();
        if(Env::get('mock.pay')) {
            $this->wxPayApi          = MockWeChatPay::instance();
            $this->dividendBonusApi  = MockWeChatProfitSharing::instance();
        } else {
            $this->wxPayApi          = new WxPay();
            $this->dividendBonusApi  = new Abonus();
        }
        $this->userOrderOp           = new UserOrderOp();
        $this->dealUserModel         = new DealUser();
        $this->dealUserCapitalModel  = new Capital();
        $this->userAccountOp         = new UserAccountOp();
        $this->dealUserAccountOp     = new DealUserAccountOp();

    }
}